﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace AL100.Samples.Delegates
{
    //STEP 1 : Avant de pouvoir utiliser un 
    // delegate, il nous faut le déclarer.
    // La déclaration d'un delegate définissant
    // un nouveau type référénce, sa déclaration 
    // doit se faire en dehors des classes.
    public delegate void PrintDelegate();
    public delegate long CalculationDelegate(int a, int b);


    /// <summary>
    /// 
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            TestPrintDelegate();
        }

        /// <summary>
        /// Tests the PrintDelegate delegate.
        /// </summary>
        public static void TestPrintDelegate()
        {
            // STEP 2 : on va maintenant déclarer une variable
            //          du type du delegate.
            PrintDelegate del;


            // STEP 3 : On va maintenant instancier notre variable del
            //          en lui passant en paramètre de son constructeur
            //          la méthode vers laquelle il faut qu'il pointe.
            del = new PrintDelegate(PrintHello);

            // STEP 4 : On veut maintenant exécuter la (ou les) méthodes
            //          stockée(s) dans le delegate..
            del();
            Console.WriteLine();

            // STEP 3 (bis): On veut maintenant ajouter la méthode
            //               PrintBye au delegate del, ce qui se fait 
            //               avec l'opérateur +=..
            del += new PrintDelegate(PrintBye);
            del();
            Console.WriteLine();

            // STEP 3 (ter): On veut maintenant supprimer la méthode
            //               PrintHello au delegate del, ce qui se fait 
            //               avec l'opérateur -=..
            del -= new PrintDelegate(PrintHello);
            del();



        }



        /// <summary>
        /// Tests the CalculationDelegate delegate.
        /// </summary>
        public static void TestCalculationDelegate()
        {
            // STEP 2 : on va maintenant déclarer une variable
            //          du type du delegate.
            CalculationDelegate del;


            // STEP 3 : On va maintenant instancier notre variable del
            //          en lui passant en paramètre de son constructeur
            //          la méthode vers laquelle il faut qu'il pointe.
            del = new CalculationDelegate(Add);

            // STEP 4 : On veut maintenant exécuter la (ou les) méthodes
            //          stockée(s) dans le delegate..
            del(12,15);
            Console.WriteLine();

            // STEP 3 (bis): On veut maintenant ajouter la méthode
            //               Substract au delegate del, ce qui se fait 
            //               avec l'opérateur +=..
            del += new CalculationDelegate(Substract);
            del(80,20);
            Console.WriteLine();

            // STEP 3 (ter): On veut maintenant supprimer la méthode
            //               Add au delegate del, ce qui se fait 
            //               avec l'opérateur -=..
            del -= new CalculationDelegate(Add);
            del(70,30);



        }


        /// <summary>
        /// Tests the print methods of delegate.
        /// </summary>
        public static void TestPrintMethodsOfDelegate()
        {
           
            PrintDelegate del;
            del = new PrintDelegate(PrintHello);
            del += new PrintDelegate(PrintBye);
            
            Console.WriteLine();

            PrintMethodsOfDelegate(del);
        }


        /// <summary>
        /// Prints the methods of delegate.
        /// </summary>
        /// <param name="del">The delegate.</param>
        public static void PrintMethodsOfDelegate(Delegate del)
        {
            foreach (Delegate containedDelegate in del.GetInvocationList())
            {
                // On récupère un objet System.Reflection.MethodInfo
                // réprésentant la méthode en cours dans la boucle vers 
                // laquelle pointe le delegate..
                MethodInfo method = containedDelegate.Method;

                Console.WriteLine("{0}.{1}",
                                  method.DeclaringType.ToString(),
                                  method.ToString());

            }
        }

       
        #region -- Méthodes de test -- 
        
        /// <summary>
        /// Prints  hello.
        /// </summary>
        public static void PrintHello()
        {
            Console.WriteLine("hello");
        }

        /// <summary>
        /// Prints bye.
        /// </summary>
        public static void PrintBye()
        {
            Console.WriteLine("bye");
        }

        public static long Add(int x, int y)
        {
            return x + y;
        }

        public static long Substract(int x, int y)
        {
            return x - y;
        }



        #endregion

    }
}
